<?php

namespace app\common\library;

use alipay\aop\AopClient;
use alipay\aop\request\AlipayTradeAppPayRequest;
use app\common\controller\Api;
use app\common\model\events\Sign;
use app\common\model\MoneyLog;
use app\common\model\order\Order;
use app\common\model\recharge\Order as RechargeOrder;
use app\common\model\User;
use app\common\model\user\Info;
use think\Db;
use think\Env;
use think\Hook;
use think\Log;

/**
 * 统一支付接口
 */
class Pay extends Api
{
    protected $noNeedLogin = ['*'];
    protected $noNeedRight = ['*'];
    protected $config;
    /**
     * 封装统一支付方法
     *
     */
    public static function pay($id, $userInfo)
    {

        Db::startTrans();
        try {
            $order = Order::get($id);
            // $order->allowField(true)->save();
            if ($order->pay_money > 0 && $order->pay_fee > 0) {
                if ($order->pay_money > $userInfo->money) {
                    exception('余额不足');
                }
            } elseif ($order->pay_money > 0 && $order->pay_fee <= 0) {
                self::yue($order);
            }
            if ($order->order_class == 3) {
                if ($order->pay_point > 0 && $order->pay_fee > 0) {
                    if ($order->pay_point > $userInfo->score) {
                        exception('积分不足');
                    }
                } elseif ($order->pay_point > 0 && $order->pay_fee <= 0) {
                    self::point($order);
                }
            }

            if ($order->pay_fee > 0) {
                //微信小程序支付
                $jsapi = Pay::minipay($order->sn, $order->pay_fee, $userInfo->openid);
                $sdk = [
                    'timeStamp' => (string) $jsapi['timeStamp'],
                    'nonceStr' => $jsapi['nonceStr'],
                    'package' => $jsapi['package'],
                    'signType' => $jsapi['signType'],
                    'paySign' => $jsapi['paySign'],
                ];
            } else {
                self::orderFulfillment($order->sn);
            }
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            exception($e->getMessage());
        }
        return $sdk ?? '';
    }

    /**
     * 余额支付
     *
     */
    private static function yue($data, $payPwd = '')
    {

        $user = User::get($data['user_id']);

        // if ($user->pay_pwd != md5(md5($payPwd) . 'pcy')) {
        //     exception('支付密码不正确');
        // }

        if ($data['pay_money'] > $user->money) {
            exception('余额不足');
        }
        Db::startTrans();
        try {
            if ($data['pay_money'] > 0) {
                User::money(-$data['pay_money'], $data['user_id'], '余额支付商品');
            }
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            exception($e->getMessage());
        }
        return true;
    }
    /**
     * 积分支付
     *
     */
    private static function point($data)
    {

        $user = User::get($data['user_id']);

        if ($data['pay_point'] > $user->score) {
            exception('积分不足');
        }
        Db::startTrans();
        try {
            if ($data['pay_point'] > 0) {
                User::score(-$data['pay_point'], $data['user_id'], '积分支付商品');
            }
            // self::orderFulfillment($data['sn']);
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();

            exception($e->getMessage());
        }
        return true;
    }


    //小程序下单
    public static function minipay($sn, $pay_fee, $openid, $attach = 'order')
    {
        $out_trade_no = $sn;
        $money = $pay_fee;

        if (empty($out_trade_no)) {
            exception('缺少参数order_sn');
        }
        // 官方提供网址
        $url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
        $urlarr = parse_url($url); //拆解为：[scheme=>https,host=>api.mch.weixin.qq.com,path=>/v3/pay/transactions/native]
        $time = time(); //时间戳
        $noncestr = self::getNonceStr();
        $appid = Env::get('wechat.min_app_id'); //appID
        $mchid = Env::get('wechat.mchid'); //商户ID
        $xlid = Env::get('wechat.xlid'); //证书序列号


        $data['appid'] = $appid;
        $data['mchid'] = $mchid;
        $data['attach'] = $attach;
        $data['description'] = '商品描述'; //商品描述
        $data['out_trade_no'] = $out_trade_no; //订单编号，订单号在微信支付里是唯一的
        $data['notify_url'] = cdnurl('/api/notify/wechatNotify', true); //需根据自己的情况修改回调接口，也可以为空
        $data['amount']['total'] = round($money * 100, 0); //金额 单位 分
        $data['scene_info']['payer_client_ip'] = $_SERVER["REMOTE_ADDR"];; //场景ip
        $data['payer']['openid'] = $openid; //openid
        $array = json_encode($data, JSON_UNESCAPED_UNICODE);
        //签名，包含了$data数据、微信指定地址、随机数和时间
        $key = self::getSign($array, $urlarr['path'], $noncestr, $time);
        $token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%d",signature="%s"', $mchid, $xlid, $noncestr, $time, $key);
        //头部信息
        $header = array(
            'Accept: application/json',
            'Content-Type: application/json',
            'User-Agent:*/*',
            'Authorization: WECHATPAY2-SHA256-RSA2048 ' . $token
        );
        $res = self::curl_post_https($url, $array, $header);

        Log::info($res);
        $prepay_id = json_decode($res, true)['prepay_id'];
        $paySign = self::getWechartSign($appid, $time, $noncestr, 'prepay_id=' . $prepay_id);
        $payData = [
            'timeStamp' => (string) $time,
            'nonceStr' => $noncestr,
            'package' => 'prepay_id=' . $prepay_id,
            'signType' => 'RSA',
            'paySign' => $paySign
        ];
        return $payData;
    }
    //订单支付成功
    public static function orderFulfillment($sn, $transaction_id = null)
    {
        $time = time();
        Db::startTrans();
        try {
            $order = Order::where('sn', $sn)->where('order_status', 0)->find(); //, ['goods']);
            if ($order) {
                if ($order->pay_money > 0 && $order->pay_fee > 0) {
                    self::yue($order);
                }
                if ($order->pay_point > 0 && $order->pay_fee > 0) {
                    self::point($order);
                }
                $user = User::get($order->user_id);
                if ($order->order_class == 2) {
                    if ($user->num <= 1) {
                        $user->num = 0;
                    } else {
                        $user->setDec('num');
                    }
                    db('share_log')->insert([
                        'user_id' => $user->id,
                        'num' => $user->num,
                        'count' => $user->count,
                        'createtime' => $time,
                        'order_id' => $order->id,
                        'uid' => $order->user_id,
                        'type' => 1,
                    ]);
                }
                $check = Order::where('sn', '<>', $sn)->where('user_id', $order['user_id'])->where('order_status', '>', 0)->where('order_class', '<>', 3)->count();
                if ($user->pid && $order->order_class != 3 && !$check && $user->first == 1) {
                    $puser = User::get($user->pid);
                    if ($puser) {
                        if ($puser->count >= 2) {
                            $puser->num += 1;
                            $puser->count = 0;
                        } else {
                            $puser->count += 1;
                        }
                        $puser->save();
                        db('share_log')->insert([
                            'user_id' => $puser->id,
                            'num' => $puser->num,
                            'count' => $puser->count,
                            'createtime' => $time,
                            'order_id' => $order->id,
                            'uid' => $order->user_id,
                            'type' => 2
                        ]);
                        $user->first = 0;
                    }
                }
                $user->save();
                $order->order_status = '10';
                $order->paytime = $time;
                $order->transaction_id = $transaction_id;
                $order->save();
                if ($order->order_class == 1) {
                    if ($order->total_fee > 0) {
                        User::score(floor($order->total_fee), $order->user_id, '购买商品，赠送积分');
                    }
                    Hook::listen("order_pay_ok", $order);
                } elseif ($order->order_class == 2) {
                    User::update(['is_exp' => 1], ['id' => $order->user_id]);
                }
            }
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            Log::error('支付异常' . var_export($e, 1));
            exception($e->getMessage());
        }
    }

    //获取随机字符串
    public static function getNonceStr()
    {
        $strs = "QWERTYUIOPASDFGHJKLZXCVBNM1234567890";
        $name = substr(str_shuffle($strs), mt_rand(0, strlen($strs) - 11), 32);
        return $name;
    }

    //微信支付签名
    public static function getSign($data, $url, $randstr = '', $time = '')
    {
        $str = "POST" . "\n" . $url . "\n" . $time . "\n" . $randstr . "\n" . $data . "\n";
        $key = file_get_contents(ROOT_PATH . str_replace('/', DS, substr('/application/certs/apiclient_key.pem', 1))); //在商户平台下载的秘钥,读取到变量
        $str = self::getSha256WithRSA($str, $key);
        return $str;
    }

    //调起支付的签名
    public static function getWechartSign($appid, $timeStamp, $noncestr, $prepay_id)
    {
        $str = $appid . "\n" . $timeStamp . "\n" . $noncestr . "\n" . $prepay_id . "\n";
        $key = file_get_contents(ROOT_PATH . str_replace('/', DS, substr('/application/certs/apiclient_key.pem', 1))); //在商户平台下载的秘钥,读取到变量
        $str = self::getSha256WithRSA($str, $key);
        return $str;
    }

    //加密
    public static function getSha256WithRSA($content, $privateKey)
    {
        $binary_signature = "";
        $algo = "SHA256";
        openssl_sign($content, $binary_signature, $privateKey, $algo);
        $sign = base64_encode($binary_signature);
        return $sign;
    }

    /* PHP CURL HTTPS POST */
    public static function curl_post_https($url, $data, $header)
    { // 模拟提交数据函数
        $curl = curl_init(); // 启动一个CURL会话
        curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); // 从证书中检查SSL加密算法是否存在，如果出错则修改为0，默认为1
        curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
        curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
        curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data); // Post提交的数据包
        curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环
        curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        $tmpInfo = curl_exec($curl); // 执行操作
        if (curl_errno($curl)) {
            echo 'Errno' . curl_error($curl); //捕抓异常
        }
        curl_close($curl); // 关闭CURL会话
        return $tmpInfo; // 返回数据，json格式
    }
}
